﻿using BenchmarkDotNet.Attributes;
using System.Runtime.InteropServices;
using System.Text;

namespace PerformanceTesting
{
    [MemoryDiagnoser]
    public class CGoStringWrapper
    {
        [DllImport("golang_demo.dll", EntryPoint = "GetString", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        public static extern GoString GetString();

        [DllImport("golang_demo.dll", EntryPoint = "GetCString", CharSet = CharSet.Unicode, ExactSpelling = false)]
        public static extern IntPtr GetCString();

        [DllImport("golang_demo.dll", EntryPoint = "FreeCString", CharSet = CharSet.Unicode, ExactSpelling = false)]
        public static extern void FreeCString(IntPtr cgoString);

        /// <summary>
        /// 测试整型类型在go语言中内存占用
        /// </summary>
        /// <param name="cgoString"></param>
        [DllImport("golang_demo.dll", EntryPoint = "VarLength", CharSet = CharSet.Unicode, ExactSpelling = false)]
        public static extern void VarLength();

        /// <summary>
        /// 测试整型类型在go语言中内存占用
        /// </summary>
        /// <param name="cgoString"></param>
        [DllImport("golang_demo.dll", EntryPoint = "GetChineseString", CharSet = CharSet.Unicode, ExactSpelling = false)]
        public static extern GoString GetChineseString();

        /// <summary>
        /// 测试整型类型在go语言中内存占用
        /// </summary>
        /// <param name="cgoString"></param>
        [DllImport("golang_demo.dll", EntryPoint = "InputGoString", CharSet = CharSet.Unicode, ExactSpelling = false)]
        public static extern IntPtr InputGoString(IntPtr goString);

        /// <summary>
        /// 测试转换go语言返回的字符串到C#字符串类型
        /// <para>使用内存数据拷贝</para>
        /// </summary>
        [Benchmark]
        public void GetGolangStringByMemoryCopy()
        {
            GoString goStr = GetString();
            byte[] manageArray = new byte[goStr.n];
            Marshal.Copy(goStr.p, manageArray, 0, goStr.n);
            Encoding.UTF8.GetString(manageArray);
        }

        /// <summary>
        /// 直接读取内存进行实例化
        /// </summary>
        public void GetGolangStringByDirectRead()
        {
            GoString goStr = GetString();
            unsafe
            {
                //Span<byte> memory = new Span<byte>(goStr.p.ToPointer(), goStr.n);
                string rtnValue = new string((sbyte*)goStr.p.ToPointer(), 0, goStr.n, Encoding.UTF8);
                Console.WriteLine(rtnValue);
            }
        }

        [Benchmark]
        public void TestMethod1()
        {
            Thread.Sleep(10 * DateTimeOffset.Now.Second);
        }

        /// <summary>
        /// 测试整型类型的内存占用
        /// </summary>
        public void IntegerTypeMemoryLength()
        {
            CGoStringWrapper.VarLength();
        }

        /// <summary>
        /// 测试go 类型的返回值字符串中包含中文
        /// </summary>
        public void TestGetChineseString()
        {
            GoString goString = GetChineseString();
            unsafe
            {
                string rtnValue = new string((sbyte*)goString.p.ToPointer(), 0, goString.n, Encoding.UTF8);
                Console.WriteLine(rtnValue);
            }
        }

        /// <summary>
        /// 测试go 类型的返回值字符串中包含中文
        /// <para>可正常运行</para>
        /// </summary>
        public void TestInputGoString()
        {
            string content = "我爱你中国!";
            byte[] content_data = Encoding.UTF8.GetBytes(content);

            unsafe
            {
                fixed (byte* a = &content_data[0])
                {
                    IntPtr intptr = IntPtr.Zero;
                    IntPtr resultPtr = IntPtr.Zero;
                    try
                    {
                        intptr = new IntPtr(a);
                        string? content1 = Marshal.PtrToStringUTF8(intptr);
                        if (content1 != null)
                        {
                            Console.WriteLine(content1);
                        }
                        else
                        {
                            Console.WriteLine("读取内存失败");
                        }

                        resultPtr = InputGoString(intptr);

                        string? rtnValue = Marshal.PtrToStringUTF8(resultPtr);//.new string((sbyte*)goString.p.ToPointer(), 0, goString.n, Encoding.UTF8);
                        Console.WriteLine(rtnValue);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex);
                    }
                    finally
                    {
                        Marshal.FreeHGlobal(intptr);
                        FreeCString(resultPtr);
                    }
                }
            }
        }
    }
}
